//
// Created by wkm on 2024-04-18.
//

#ifndef AES128CHIPSYSTEMC_MIXCOLUMNS_H
#define AES128CHIPSYSTEMC_MIXCOLUMNS_H

#include "../core_module/CONSTANT.h"
#include "../FiniteFieldMul/x2time.h"
#include "../FiniteFieldMul/x3time.h"

enum element_state {
    row_1_col_1 = 0, row_2_col_1, row_3_col_1, row_4_col_1,
    row_1_col_2, row_2_col_2, row_3_col_2, row_4_col_2,
    row_1_col_3, row_2_col_3, row_3_col_3, row_4_col_3,
    row_1_col_4, row_2_col_4, row_3_col_4, row_4_col_4,
    OVER
};

SC_MODULE(mixcolumns) {
    sc_in<bool> clk, start, reset;
    sc_in<sc_uint<DATA_SIZE>> input_data_1, input_data_2, input_data_3, input_data_4,
            input_data_5, input_data_6, input_data_7, input_data_8,
            input_data_9, input_data_10, input_data_11, input_data_12,
            input_data_13, input_data_14, input_data_15, input_data_16;
    sc_out<sc_uint<DATA_SIZE>> out_data_1, out_data_2, out_data_3, out_data_4,
            out_data_5, out_data_6, out_data_7, out_data_8,
            out_data_9, out_data_10, out_data_11, out_data_12,
            out_data_13, out_data_14, out_data_15, out_data_16;
    sc_out<exe_state> done;

    sc_uint<DATA_SIZE> temp_input_data[16];
    sc_uint<DATA_SIZE> temp_result[16];

    sc_signal<exe_state> x2_done, x3_done;
    sc_signal<sc_uint<DATA_SIZE>> x2_input_data, x3_input_data, x2_output_data, x3_output_data;
    sc_signal<bool> x23_reset, x23_start;
    sc_signal<sc_uint<DATA_SIZE>> x2_compute_times;

    x2time *x2;
    x3time *x3;

    element_state next_state, state;
    exe_state x23_prepare, next_done;

    void prc_mixcolumns();

    SC_CTOR(mixcolumns) {
        x2 = new x2time("mixcolumns_x2");
        x2->compute_times(x2_compute_times);
        x3 = new x3time("mixcolumns_x3");

        x2->reset(x23_reset);
        x3->reset(x23_reset);

        x2->start(x23_start);
        x3->start(x23_start);

        x2->input_data(x2_input_data);
        x3->input_data(x3_input_data);

        x2->result(x2_output_data);
        x3->result(x3_output_data);

        x2->done(x2_done);
        x3->done(x3_done);

        x2->clk(clk);
        x3->clk(clk);


        SC_METHOD(prc_mixcolumns);
        sensitive << clk.pos();
    }

    ~mixcolumns() {
        delete x2;
        delete x3;
    }
};

#endif //AES128CHIPSYSTEMC_MIXCOLUMNS_H
